/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package shaman.storage.impl.stream.gather;

import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 *
 * @author dmitriy
 */
public class GatherOutputStream {

    private final OutputStream baseStream;
    private boolean streamOpen;
    private boolean streamClosed;
    private long offset;

    private class PartOutputStream extends FilterOutputStream {

        private boolean closed;
        private final GatherPartListener plist;
        private final long startOffset;

        public PartOutputStream(GatherPartListener plist) {
            super(baseStream);
            closed=false;
            this.plist=plist;
            startOffset=offset;
        }

        @Override
        protected Object clone() throws CloneNotSupportedException {
            throw new CloneNotSupportedException("Clone not supported");
        }

        @Override
        public synchronized void close() throws IOException {
            if (closed==false)
            {
                closed=true;
                if (plist!=null)
                    plist.partAdded(startOffset, offset);
                streamOpen=false;
            }
        }

        @Override
        public synchronized void flush() throws IOException {
            if (!closed)
                out.flush();
            else
                throw new IOException("Stream closed");
        }

        @Override
        public synchronized void write(int b) throws IOException {
            if (!closed)
            {
                out.write(b);
                offset++;
            }
            else
                throw new IOException("Stream closed");
        }

        @Override
        public synchronized void write(byte[] b, int off, int len) throws IOException {
            if (!closed)
            {
                out.write(b, off, len);
                offset+=len;
            }
            else
                throw new IOException("Stream closed");
        }

    }

    public GatherOutputStream(OutputStream baseStream) {
        this.baseStream=baseStream;
        streamOpen=false;
        streamClosed=false;
        offset=0;
    }

    public synchronized OutputStream nextPart(GatherPartListener plist) throws IOException
    {
        if (streamClosed)
            throw new IOException("The stream is already closed");
        if (streamOpen)
            throw new IOException("A stream is already opened");
        streamOpen=true;
        return new PartOutputStream(plist);
    }

    public void close() throws IOException {
        streamClosed=true;
        baseStream.close();
    }
}
